﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;

namespace Microsoft.OpportunityPortal
{
    /// <summary>
    /// This class contains the functions to perform operation on SharePoint components
    /// such as list, web, security, etc.
    /// </summary>
    public class SPOperations
    {
        /// <summary>
        /// Marks the field as hidden in list
        /// </summary>
        /// <param name="SiteURL">Site URL</param>
        /// <param name="ListName">List Name</param>
        /// <param name="ColumnName">Name of the column to hide</param>
        public static void HideField(string SiteURL, string ListName, string ColumnName)
        {
            using (SPSite site = new SPSite(SiteURL))
            {
                using (SPWeb oppWeb = site.OpenWeb())
                {
                    SPList caseStudyRef = oppWeb.Lists[ListName];
                    SPField field = caseStudyRef.Fields.GetField(ColumnName);
                    field.ShowInViewForms = false;
                    field.ShowInNewForm = false;
                    field.ShowInDisplayForm = false;
                    field.ShowInEditForm = false;
                    field.Update(true);
                }
            }
        }

        /// <summary>
        /// Adds the field to list view
        /// </summary>
        /// <param name="SiteURL">Site URL</param>
        /// <param name="ListName">List Name</param>
        /// <param name="columnNames">List containing column names</param>
        public static void AddFieldToView(string siteURL, string listName, List<string> columnNames)
        {
            using (SPSite site = new SPSite(siteURL))
            {
                using (SPWeb oppWeb = site.OpenWeb())
                {
                    SPList caseStudyRef = oppWeb.Lists[listName];
                    SPView view = caseStudyRef.DefaultView;

                    foreach (string columnName in columnNames)
                    {
                        view.ViewFields.Add(columnName);
                    }

                    view.Update();

                }
            }
        }

        /// <summary>
        /// Update lookup field
        /// </summary>
        /// <param name="SiteURL">Site URL</param>
        /// <param name="ListName">List Name</param>
        /// <param name="lookupColumnName">Lookup Column Name</param>
        public static void UpdateLookupField(string SiteURL, string ListName, string lookupColumnName)
        {
            using (SPSite site = new SPSite(SiteURL))
            {
                using (SPWeb oppWeb = site.OpenWeb())
                {
                    SPList caseStudyRef = oppWeb.Lists[ListName];
                    SPField field = caseStudyRef.Fields.GetField(lookupColumnName);
                    field.Delete();

                    caseStudyRef.Fields.Add(oppWeb.ParentWeb.Fields.GetField(lookupColumnName));
                    caseStudyRef.Update();
                }
            }
        }

        /// <summary>
        /// Creates group and also assigns permission to the web
        /// </summary>
        /// <param name="siteCollectionURL">Site Collection URL</param>
        /// <param name="portalSiteURL">Portal Site URL - use it for logging the errors</param>
        /// <param name="GroupName">Group Name</param>
        /// <param name="GroupDesc">Group Description</param>
        /// <param name="roleName">Permission Level</param>
        public static void CreateGroup(string siteCollectionURL, string portalSiteURL, string GroupName, string GroupDesc, string roleName)
        {
            try
            {
                //create the user groups ...
                using (SPSite site = new SPSite(siteCollectionURL))
                {
                    using (SPWeb oppWeb = site.OpenWeb())
                    {
                        // Create Group
                        SPMember member = oppWeb.EnsureUser(oppWeb.Author.LoginName);
                        //SPMember member = oppWeb.Users[oppWeb.Author.LoginName];

                        // Check if the system account exists or not
                        oppWeb.SiteGroups.Add(GroupName, member, oppWeb.Author, GroupDesc);
                        SPGroup newGroup = oppWeb.SiteGroups[GroupName];

                        // Assign Permission Level
                        SPRoleDefinition role = oppWeb.RoleDefinitions[roleName];
                        SPRoleAssignment roleAssignment = new SPRoleAssignment(newGroup);
                        roleAssignment.RoleDefinitionBindings.Add(role);
                        oppWeb.RoleAssignments.Add(roleAssignment);
                        oppWeb.Update();
                    }
                }
            }
            catch (Exception expn)
            {
                Dictionary<string, string> errorLog = new Dictionary<string, string>();
                errorLog.Add("Title", "Error_" + DateTime.Now.ToLongTimeString());
                errorLog.Add("Description", string.Format("StackTrace={0},Message={1}", expn.StackTrace, expn.Message));
                errorLog.Add("EventType", "Error");

                SPOperations.AddUpdateListItem(portalSiteURL, "Logger", errorLog, SPEventType.Add);
            }
        }

        /// <summary>
        /// Creates permission group, assigns permission and adds users
        /// </summary>
        /// <param name="SiteURL"></param>
        /// <param name="GroupName"></param>
        /// <param name="GroupDesc"></param>
        /// <param name="roleType"></param>
        /// <param name="users"></param>
        public static void CreateGroup(string parentSiteURL, string SiteURL, string GroupName, string GroupDesc, SPRoleType roleType,
            SPFieldUserValueCollection users, bool isSystemAcountGrpOwner, string groupOwnerName)
        {
            try
            {
                // create the user groups ...
                using (SPSite site = new SPSite(SiteURL))
                {
                    using (SPWeb oppWeb = site.OpenWeb())
                    {
                        // Create Group
                        SPMember member = oppWeb.EnsureUser(oppWeb.Author.LoginName);
                        //SPMember member = oppWeb.Users[oppWeb.Author.LoginName];

                        // Check if the system account exists or not
                        oppWeb.SiteGroups.Add(GroupName, member, oppWeb.Author, GroupDesc);
                        SPGroup newGroup = oppWeb.SiteGroups[GroupName];

                        // Check if the system account should be the owner group else make the group itself owner
                        if (false == isSystemAcountGrpOwner)
                        {
                            if (oppWeb.SiteGroups[groupOwnerName] != null)
                            {
                                SPGroup ownerGroup = oppWeb.SiteGroups[groupOwnerName];
                                newGroup.Owner = ownerGroup;
                            }
                        }

                        // Assign Permission Level
                        SPRoleDefinition role = oppWeb.RoleDefinitions.GetByType(roleType);
                        SPRoleAssignment roleAssignment = new SPRoleAssignment(newGroup);
                        roleAssignment.RoleDefinitionBindings.Add(role);
                        oppWeb.RoleAssignments.Add(roleAssignment);

                        // Add users
                        if (users != null && users.Count > 0)
                        {
                            foreach (SPFieldUserValue user in users)
                            {
                                newGroup.AddUser(user.User);
                            }
                        }

                        // Update group
                        newGroup.Update();
                    }
                }
            }
            catch (Exception expn)
            {
                Dictionary<string, string> errorLog = new Dictionary<string, string>();
                errorLog.Add("Title", "Error_" + DateTime.Now.ToLongTimeString());
                errorLog.Add("Description", string.Format("StackTrace={0},Message={1}", expn.StackTrace, expn.Message));
                errorLog.Add("EventType", "Error");

                SPOperations.AddUpdateListItem(parentSiteURL, "Logger", errorLog, SPEventType.Add);
            }
        }

        public static void AssignGroupToSPWeb(string siteURL, string groupName, string permissionLevel)
        {
            try
            {
                using (SPSite spsite = new SPSite(siteURL))
                {
                    using (SPWeb web = spsite.OpenWeb())
                    {
                        web.AllowUnsafeUpdates = true;

                        // Retrieve group
                        SPGroup sgrp = web.SiteGroups[groupName];

                        // Assign Permission Level
                        SPRoleDefinition roleDefinition = web.RoleDefinitions[permissionLevel];
                        SPRoleAssignment roleAssignment = new SPRoleAssignment((SPPrincipal)sgrp);
                        roleAssignment.RoleDefinitionBindings.Add(roleDefinition);
                        web.RoleAssignments.Add(roleAssignment);
                        web.Update();
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// Create Permission Level
        /// </summary>
        /// <param name="siteURL">Root Site URL</param>
        /// <param name="roleName">Role Name</param>
        /// <param name="desc">Role Description</param>
        /// <param name="roleDef">Role Definition</param>
        /// <returns>Returns true if created successfully.</returns>
        public static bool CreatePermissionLevel(string siteURL, string roleName, string desc, SPRoleDefinition roleDef)
        {
            bool result = false;

            try
            {
                using (SPSite site = new SPSite(siteURL))
                {
                    using (SPWeb web = site.OpenWeb())
                    {
                        if (web.HasUniqueRoleDefinitions || web.IsRootWeb)
                        {
                            web.AllowUnsafeUpdates = true;
                            roleDef.Name = roleName;
                            roleDef.Description = desc;
                            web.RoleDefinitions.Add(roleDef);
                            web.Update();
                            result = true;
                        }
                    }
                }
            }
            catch (Exception)
            {
                // Kill the exception as it will be thrown only when the permission level exists. This
                // condition occurswhen multiple opportunity portal exists under same site collection
            }

            return result;
        }

        /// <summary>
        /// Adds or updates the list item
        /// </summary>
        /// <param name="SiteURL">Site URL</param>
        /// <param name="ListName">List Name</param>
        /// <param name="fieldsWithValues">Fields containing values to update</param>
        /// <param name="eventType">EventType</param>
        public static void AddUpdateListItem(string siteURL, string listName, Dictionary<string, string> fieldsWithValues, SPEventType eventType)
        {
            // Return if the dictionary doesn't contain fields to update
            if (fieldsWithValues.Count < 1)
            {
                return;
            }

            using (SPSite site = new SPSite(siteURL))
            {
                using (SPWeb oppWeb = site.OpenWeb())
                {
                    SPList list = oppWeb.Lists[listName];

                    SPListItem addedItem = list.Items.Add();

                    foreach (KeyValuePair<string, string> item in fieldsWithValues)
                    {
                        addedItem[item.Key] = item.Value;
                    }

                    addedItem.Update();
                }
            }
        }

        /// <summary>
        /// Return the lookup id 
        /// </summary>
        /// <param name="str">Lookup column value string</param>
        /// <returns>Lookup ID</returns>
        public static int ReturnLookupID(string str)
        {
            int itemId = 0;
            string[] values = str.Split(";#".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            if (values.Count() == 2)
            {
                int.TryParse(values[0], out itemId);
            }

            return itemId;
        }

        /// <summary>
        /// Check if the current logged in user is a member of group or not.
        /// </summary>
        /// <param name="siteURL"></param>
        /// <param name="url"></param>
        /// <param name="groupNames"></param>
        /// <returns></returns>
        public static bool IsMember(string siteURL, List<string> groupNames)
        {
            bool isMember = false;
            using (SPSite site = new SPSite(siteURL))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    foreach (string groupName in groupNames)
                    {
                        int count = web.Site.RootWeb.Groups.Count; // Call this method to get the groups otherwise below exprn throws exception.
                        SPGroup group = null;

                        foreach (SPGroup grp in web.Site.RootWeb.Groups)
                        {
                            if (string.Compare(grp.Name, groupName, true) == 0)
                            {
                                group = grp;
                                break;
                            }
                        }

                        if (group != null)
                        {
                            // Check if the current user is site admin or not. if yes then allow approval. 
                            // This condition occurs when task is approved under SharePoint/system credentials.
                            isMember = web.Site.RootWeb.IsCurrentUserMemberOfGroup(group.ID);
                            if (true == isMember || true == web.UserIsSiteAdmin)
                            {
                                isMember = true;
                                break;
                            }
                        }
                    }
                }

            }

            return isMember;
        }

        /// <summary>
        /// Compare the users and return true if matches.
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public static bool IsUserItemCreator(string userName, SPItemEventProperties properties)
        {
            userName = userName.ToLower();

            if (userName.Contains('#'))
            {
                userName = userName.Substring(userName.IndexOf('#') + 1);
            }

            // Compare user name with the login name. Return true if matches.
            return properties.Web.CurrentUser.LoginName.ToLower().Contains(userName);
        }

        /// <summary>
        /// Associates workflow to the OpportunityRequest content type
        /// </summary>
        /// <param name="siteURL">Site URL</param>
        /// <param name="contentTypeName">Content Type Name</param>
        /// <param name="workflowName">Workflow Name</param>
        /// <param name="taskListTitle">Task List Title</param>
        /// <param name="historyListTitle">History Title</param>
        public static void AssociateWorkflow(string siteURL, string contentTypeName, string workflowName, string taskListTitle, string historyListTitle)
        {
            try
            {
                using (SPSite siteCollection = new SPSite(siteURL))
                {
                    using (SPWeb site = siteCollection.OpenWeb())
                    {
                        SPContentType siteContentType = site.ContentTypes[contentTypeName];

                        // Get a template.
                        SPWorkflowTemplate workflowTemplate = null;
                        foreach (SPWorkflowTemplate template in site.WorkflowTemplates)
                        {
                            if (template.Name == workflowName)
                            {
                                workflowTemplate = template;
                                break;
                            }
                        }

                        // check if the workflow exists or not. If not then return 
                        if (workflowTemplate == null)
                        {
                            return;
                        }

                        // Create an association.
                        SPWorkflowAssociation workflowAssociation =
                            SPWorkflowAssociation.CreateWebContentTypeAssociation(workflowTemplate,
                                                                                   workflowName,
                                                                                   taskListTitle,
                                                                                   historyListTitle);

                        // Allow workflow to start manually, on new item add or item change eventhistoryListTitle);
                        workflowAssociation.AutoStartChange = true;
                        workflowAssociation.AutoStartCreate = true;
                        workflowAssociation.AllowManual = true;

                        // Add the association to the content type or update it if it already exists.
                        if (siteContentType.WorkflowAssociations.GetAssociationByName(workflowAssociation.Name, site.Locale) == null)
                        {
                            siteContentType.WorkflowAssociations.Add(workflowAssociation);
                            Console.WriteLine("added.");
                        }
                        else
                        {
                            siteContentType.WorkflowAssociations.Update(workflowAssociation);
                            Console.WriteLine("updated.");
                        }

                        // Propagate to children of this content type.
                        siteContentType.UpdateWorkflowAssociationsOnChildren(false,  // Do not generate full change list
                                                                             true,   // Push down to derived content types
                                                                             true,   // Push down to list content types
                                                                             false); // Do not throw exception if sealed or readonly  
                    }
                }

            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// Adds list item
        /// </summary>
        /// <param name="SiteURL">Site URL</param>
        /// <param name="ListName">List Name</param>
        /// <param name="values">List Item Field Values</param>
        /// <returns>Return true if added successfully/.</returns>
        public static bool AddListItem(string siteURL, string listName, Dictionary<string, object> values)
        {
            bool result = true;
            try
            {
                using (SPSite site = new SPSite(siteURL))
                {
                    using (SPWeb web = site.OpenWeb())
                    {
                        SPList list = web.GetList("/Lists/" + siteURL);

                        if (list != null)
                        {
                            SPListItem item = list.AddItem();


                            foreach (KeyValuePair<string, object> keyValue in values)
                            {
                                if (item.Fields.ContainsField(keyValue.Key))
                                {
                                    item[keyValue.Key] = keyValue.Value;
                                }
                            }

                            item.UpdateOverwriteVersion();
                        }
                    }
                }
            }
            catch (Exception)
            {
                result = false;
            }

            return result;
        }
    }
}
